package org.act.BPEL2Automata.transformer;

import java.util.LinkedList;

import javax.xml.namespace.QName;

import org.act.BPEL2Automata.automata.SubAutomataImp;
import org.act.BPEL2Automata.automata.module.Message;
import org.act.BPEL2Automata.automata.module.SimpleLogicalFormulaImp;
import org.act.BPEL2Automata.automata.module.State;
import org.act.BPEL2Automata.automata.module.TransitionFunction;
import org.act.BPEL2Automata.automata.module.TransitionRule;
import org.act.BPEL2Automata.bpel.BPELParser;
import org.act.BPEL2Automata.utils.QNameUtil;
import org.act.xservices.bpel11.TAssign;
import org.act.xservices.bpel11.TEmpty;
import org.act.xservices.bpel11.TFlow;
import org.act.xservices.bpel11.TInvoke;
import org.act.xservices.bpel11.TOnAlarm;
import org.act.xservices.bpel11.TOnMessage;
import org.act.xservices.bpel11.TPick;
import org.act.xservices.bpel11.TReceive;
import org.act.xservices.bpel11.TReply;
import org.act.xservices.bpel11.TSequence;
import org.act.xservices.bpel11.TSwitch;
import org.act.xservices.bpel11.TTerminate;
import org.act.xservices.bpel11.TVariables;
import org.act.xservices.bpel11.TWait;
import org.act.xservices.bpel11.TWhile;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;

/**
 * transform BPEL activities(ONLY process statements) to SubAutomataImp objects.
 * @author baoxiwu<bb@feijiao.info>,ACT,Beihang University
 * @version 0.9.0
 * @since 2010-03-29
 * 
 */
public class Transformer {
	public Transformer(){
	//empty
	}
	
	//main entry.
	public SubAutomataImp transform(String filename){
		BPELParser bp = new BPELParser(filename);
		bp.parse();
		
		return this.handleSequence((TSequence)(bp.getActivityContainer().eContents().get(0)), bp.getVariables());
	}
	
	/*
	 * <annotation id = "0">
	 * echo RULE-1 of liumin's paper.
	 */
	//handle assign statement
	private SubAutomataImp handleAssign(TAssign assign){
		SubAutomataImp automata = new SubAutomataImp();
		
		SimpleLogicalFormulaImp slf = new SimpleLogicalFormulaImp(automata.getStartState(),SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		
		automata.getStartState().addSourceList(assign);
		automata.getStartState().addTargetList(assign);
		
		automata.setStateSet(automata.getStartState());
		automata.setFinalStateSet(automata.getStartState());
		automata.getLabelFunction().add(slf);
		
		return automata;
	}
	
	
	//handle empty statement
	private SubAutomataImp handleEmpty(TEmpty empty){
		SubAutomataImp automata = new SubAutomataImp();
		
		SimpleLogicalFormulaImp slf = new SimpleLogicalFormulaImp(automata.getStartState(),SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		
		automata.getStartState().addSourceList(empty);
		automata.getStartState().addTargetList(empty);
		
		automata.setStateSet(automata.getStartState());
		automata.setFinalStateSet(automata.getStartState());
		automata.getLabelFunction().add(slf);
		
		return automata;
	}
	
	
	//handle wait statement
	private SubAutomataImp handleWait(TWait wait){
		SubAutomataImp automata = new SubAutomataImp();
		
		SimpleLogicalFormulaImp slf = new SimpleLogicalFormulaImp(automata.getStartState(),SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		
		automata.getStartState().addSourceList(wait);
		automata.getStartState().addTargetList(wait);
		
		automata.setStateSet(automata.getStartState());
		automata.setFinalStateSet(automata.getStartState());
		automata.getLabelFunction().add(slf);
		
		return automata;
	}
	
	
	//echo RULE-2 of liumin's paper.
	//handle terminate statement
	private SubAutomataImp handleTerminate(TTerminate terminate){
		SubAutomataImp automata = new SubAutomataImp();
		
		SimpleLogicalFormulaImp slf = new SimpleLogicalFormulaImp(automata.getStartState(),SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		
		automata.getStartState().addSourceList(terminate);
		//automata.getStartState().addTargetList(State.BEPL_ACTIVITY_TYPE_TERMINATE);
		
		automata.setStateSet(automata.getStartState());
		automata.setTerminationStateSet(automata.getStartState());
		automata.getLabelFunction().add(slf);
		
		return automata;
	}
	/*
	 * </annotation id = "0">
	 */
	
	
	//echo RULE-3 of liumin's paper.
	//handle receive statement
	private SubAutomataImp handleReceive(TReceive receive,TVariables variables){
		SubAutomataImp automata = new SubAutomataImp();
		
		automata.getStartState().addSourceList(receive);
		
		//set state set.
		LinkedList<State> stateSet = new LinkedList<State>();
		State fstate = new State();
		
		stateSet.add(automata.getStartState());
		stateSet.add(fstate);
		
		automata.setStateSet(stateSet);
		
		
		//set final state [set].
		automata.setFinalStateSet(fstate);
		fstate.addTargetList(receive);
		
		
		//set message
		String mt = "";
		
		for(int i = 0; i < variables.getVariable().size();i++){
			if(variables.getVariable().get(i).getName().equals(receive.getVariable())){
				//$link
				//TODO ...getMessageType() returns an Object,maybe it's NOT the one I wanna get.
				QName qn = QNameUtil.translate(variables.getVariable().get(i).getMessageType());
				mt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
				
				//System.err.println("\tgetMessageType() = " + mt);
				
				//ONLY accept the first one that matches the condition,as maybe
				//the BPEL file is not 100% correct.
				break;
			}
		}
		
		//TODO TESTING WANTED.
		//System.err.println("\treceive.getPortType() = " + receive.getPortType().toString());
		QName qn = QNameUtil.translate(receive.getPortType());
		String pt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
		
		Message mes = new Message(receive.getPartnerLink(),pt,receive.getOperation(),mt,Message.MESSAGE_DIRECTION_IN);
		
		//TODO TESTING WANTED.
		mes = Message.checkUnicity(automata.getMessageSet(), mes);
		
		automata.setMessageSet(mes);
		
		
		//set label function
		SimpleLogicalFormulaImp clf = new SimpleLogicalFormulaImp(automata.getStartState(),mes,fstate);
		SimpleLogicalFormulaImp clf2 = new SimpleLogicalFormulaImp(fstate,SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		automata.getLabelFunction().add(clf);
		automata.getLabelFunction().add(clf2);
		
		
		//set transition function.
		TransitionRule tr = new TransitionRule(automata.getStartState(),mes,fstate);
		TransitionFunction tf = new TransitionFunction();
		tf.add(tr);
		
		automata.setTransitionFunction(tf);
		
		
		return automata;
	}
	
	
	//echo RULE-4 of liumin's paper.
	//handle reply statement
	private SubAutomataImp handleReply(TReply reply,TVariables variables){
		SubAutomataImp automata = new SubAutomataImp();
		
		automata.getStartState().addSourceList(reply);
		
		//set state set.
		LinkedList<State> stateSet = new LinkedList<State>();
		State fstate = new State();
		
		stateSet.add(automata.getStartState());
		stateSet.add(fstate);
		
		automata.setStateSet(stateSet);
		
		
		//set final state [set].
		automata.setFinalStateSet(fstate);
		fstate.addTargetList(reply);
		
		
		//set message
		String mt = "";
		
		for(int i = 0; i < variables.getVariable().size();i++){
			if(variables.getVariable().get(i).getName().equals(reply.getVariable())){
				//the same to $link
				QName qn = QNameUtil.translate(variables.getVariable().get(i).getMessageType());
				mt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
				
				break;
			}
		}
		
		//the same to $link
		QName qn = QNameUtil.translate(reply.getPortType());
		String pt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
		
		Message mes = new Message(reply.getPartnerLink(),pt,reply.getOperation(),mt,Message.MESSAGE_DIRECTION_OUT);
		
		//TODO TESTING WANTED.
		mes = Message.checkUnicity(automata.getMessageSet(), mes);
		
		automata.setMessageSet(mes);
		
		
		//set label function
		SimpleLogicalFormulaImp clf = new SimpleLogicalFormulaImp(automata.getStartState(),mes,fstate);
		SimpleLogicalFormulaImp clf2 = new SimpleLogicalFormulaImp(fstate,SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		automata.getLabelFunction().add(clf);
		automata.getLabelFunction().add(clf2);
		
		
		//set transition function.
		TransitionRule tr = new TransitionRule(automata.getStartState(),mes,fstate);
		TransitionFunction tf = new TransitionFunction();
		tf.add(tr);
		automata.setTransitionFunction(tf);
		
		
		return automata;
	}
	
	
	//echo RULE-4 and RULE-5 of liumin's paper.
	//handle invoke statement
	private SubAutomataImp handleInvoke(TInvoke invoke,TVariables variables){
		SubAutomataImp automata = new SubAutomataImp();
		
		//asynchronous invoke activity
		/*
		 * TODO
		 * TESTING WANTED.
		 * TInvoke's getOutputVariable() method returns null 
		 * when NO output variables found?
		 * 
		 */
		if(invoke.getOutputVariable() == null){
			automata.getStartState().addSourceList(invoke);
			
			//set state set.
			LinkedList<State> stateSet = new LinkedList<State>();
			State fstate = new State();
			
			stateSet.add(automata.getStartState());
			stateSet.add(fstate);
			
			automata.setStateSet(stateSet);
			
			
			//set final state [set].
			automata.setFinalStateSet(fstate);
			fstate.addTargetList(invoke);
			
			
			//set message
			String mt = "";
			
			for(int i = 0; i < variables.getVariable().size();i++){
				if(variables.getVariable().get(i).getName().equals(invoke.getInputVariable())){
					//the same to $link
					QName qn = QNameUtil.translate(variables.getVariable().get(i).getMessageType());
					mt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
					
					break;
				}
			}
			
			//the same to $link
			QName qn = QNameUtil.translate(invoke.getPortType());
			String pt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
			
			Message mes = new Message(invoke.getPartnerLink(),pt,invoke.getOperation(),mt,Message.MESSAGE_DIRECTION_OUT);
			
			//TODO TESTING WANTED.
			mes = Message.checkUnicity(automata.getMessageSet(), mes);
			
			automata.setMessageSet(mes);
			
			
			//set label function
			SimpleLogicalFormulaImp clf = new SimpleLogicalFormulaImp(automata.getStartState(),mes,fstate);
			SimpleLogicalFormulaImp clf2 = new SimpleLogicalFormulaImp(fstate,SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
			automata.getLabelFunction().add(clf);
			automata.getLabelFunction().add(clf2);
			
			
			//set transition function.
			TransitionRule tr = new TransitionRule(automata.getStartState(),mes,fstate);
			TransitionFunction tf = new TransitionFunction();
			tf.add(tr);
			
			automata.setTransitionFunction(tf);
			
			
			return automata;
		}
		//synchronous invoke activity
		else{
			automata.getStartState().addSourceList(invoke);
			
			//set state set.
			LinkedList<State> stateSet = new LinkedList<State>();
			State mstate = new State();
			State fstate = new State();
			
			stateSet.add(automata.getStartState());
			stateSet.add(mstate);
			stateSet.add(fstate);
			
			automata.setStateSet(stateSet);
			
			
			//set final state [set].
			automata.setFinalStateSet(fstate);
			fstate.addTargetList(invoke);
			
			
			//set message
			String inmt = "";//message type of input variable 
			String outmt = "";//message type of output variable
			
			for(int i = 0; i < variables.getVariable().size();i++){
				if(variables.getVariable().get(i).getName().equals(invoke.getInputVariable())){
					//the same to $link
					QName qn = QNameUtil.translate(variables.getVariable().get(i).getMessageType());
					inmt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
				}
				else
				if(variables.getVariable().get(i).getName().equals(invoke.getOutputVariable())){
					QName qn = QNameUtil.translate(variables.getVariable().get(i).getMessageType());
					outmt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
				}
			}
			
			//the same to $link
			QName qn = QNameUtil.translate(invoke.getPortType());
			String pt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
			
			Message mes1 = new Message(invoke.getPartnerLink(),pt,invoke.getOperation(),inmt,Message.MESSAGE_DIRECTION_OUT);
			Message mes2 = new Message(invoke.getPartnerLink(),pt,invoke.getOperation(),outmt,Message.MESSAGE_DIRECTION_IN);
			
			//TODO TESTING WANTED.
			mes1 = Message.checkUnicity(automata.getMessageSet(), mes1);
			mes2 = Message.checkUnicity(automata.getMessageSet(), mes2);
			
			automata.setMessageSet(mes1);
			automata.setMessageSet(mes2);
			
			
			//set label function
			SimpleLogicalFormulaImp clf = new SimpleLogicalFormulaImp(automata.getStartState(),mes1,mstate);
			SimpleLogicalFormulaImp clf2 = new SimpleLogicalFormulaImp(mstate,mes2,fstate);
			SimpleLogicalFormulaImp clf3 = new SimpleLogicalFormulaImp(fstate,SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
			
			automata.getLabelFunction().add(clf);
			automata.getLabelFunction().add(clf2);
			automata.getLabelFunction().add(clf3);
			
			
			//set transition function.
			TransitionRule tr1 = new TransitionRule(automata.getStartState(),mes1,mstate);
			TransitionRule tr2 = new TransitionRule(mstate,mes2,fstate);
			TransitionFunction tf = new TransitionFunction();
			tf.add(tr1);
			tf.add(tr2);
			automata.setTransitionFunction(tf);
			
			
			return automata;
		}
	}
	
	
	//structural statements
	//echo RULE-6 of liumin's paper.
	//handle sequence statement
	private SubAutomataImp handleSequence(TSequence sequence, TVariables variables){
		LinkedList<SubAutomataImp> automataList = new LinkedList<SubAutomataImp>(); 
		SubAutomataImp resultAutomata = null;
		
		for(int i = 0; i < sequence.eContents().size(); i++){
			EObject subActivity = sequence.eContents().get(i);
			
			//1.assign activity
			if(subActivity instanceof TAssign){
				automataList.add(this.handleAssign((TAssign)subActivity));
			}
			else
			//2.empty activity
			if(subActivity instanceof TEmpty){
				automataList.add(this.handleEmpty((TEmpty)subActivity));
			}
			else
			//3.flow activity
			if(subActivity instanceof TFlow){
				automataList.add(this.handleFlow((TFlow)subActivity, variables));
			}
			else
			//4.invoke activity
			if(subActivity instanceof TInvoke){
				automataList.add(this.handleInvoke((TInvoke)(subActivity), variables));
			}
			else
			//5.pick activity
			if(subActivity instanceof TPick){
				automataList.add(this.handlePick((TPick)(subActivity), variables));
			}
			else
			//6.receive activity
			if(subActivity instanceof TReceive){
				automataList.add(this.handleReceive((TReceive)(subActivity), variables));
			}
			else
			//7.reply activity
			if(subActivity instanceof TReply){
				automataList.add(this.handleReply((TReply)(subActivity), variables));
			}
			else
			//8.switch activity
			if(subActivity instanceof TSwitch){
				automataList.add(this.handleSwitch((TSwitch)(subActivity), variables));
			}
			else
			//9.terminate activity
			if(subActivity instanceof TTerminate){
				automataList.add(this.handleTerminate((TTerminate)subActivity));
			}
			else
			//1i.wait activity
			if(subActivity instanceof TWait){
				automataList.add(this.handleWait((TWait)subActivity));
			}
			else
			//11.while activity
			if(subActivity instanceof TWhile){
				automataList.add(this.handleWhile((TWhile)subActivity, variables));
			}
			else
			//12.sequence activity
			if(subActivity instanceof TSequence){
				//TODO
				//TESTING WANTED.
				automataList.add(this.handleSequence((TSequence)subActivity, variables));
			}
			else{//TODO NOT any of above activities.
				
			}
		}
		
		//M = M1 M2 M3 ... Mn
		for(int i = 0; i < automataList.size(); i++){
			if(resultAutomata == null){
				resultAutomata = automataList.get(i);
				continue;
			}
			
			resultAutomata = resultAutomata.doCatenation(automataList.get(i));
		}
		
		
		//add the TSequence reference to start and final states 
		resultAutomata.getStartState().addSourceList(sequence);
		
		for(int i = 0; i < resultAutomata.getFinalStateSet().size(); i++){
			resultAutomata.getFinalStateSet().get(i).addTargetList(sequence);
		}
		
		
		return resultAutomata;
	}
	
	
	//echo RULE-7 of liumin's paper.
	//handle switch statement
	private SubAutomataImp handleSwitch(TSwitch tSwitch,TVariables variables){
		LinkedList<SubAutomataImp> automataList = new LinkedList<SubAutomataImp>();
		SubAutomataImp resultAutomata = null;
		
		for(int i = 0; i < tSwitch.getCase().size();i++){
			//@2010-06-04 MORE THAN ONE ACTIVITY,but only one below activity.
			EList<EObject> eo = tSwitch.getCase().get(i).eContents();
			
			//add Otherwise to the list.
			//eo.addAll(tSwitch.getOtherwise().eContents());
			
			for(int j = 0; j < eo.size();j++){
				EObject subActivity = eo.get(j);
				
				//1.assign activity
				if(subActivity instanceof TAssign){
					automataList.add(this.handleAssign((TAssign)subActivity));
				}
				else
				//2.empty activity
				if(subActivity instanceof TEmpty){
					automataList.add(this.handleEmpty((TEmpty)subActivity));
				}
				else
				//3.flow activity
				if(subActivity instanceof TFlow){
					automataList.add(this.handleFlow((TFlow)subActivity, variables));
				}
				else
				//4.invoke activity
				if(subActivity instanceof TInvoke){
					automataList.add(this.handleInvoke((TInvoke)subActivity,variables));
				}
				else
				//5.pick activity
				if(subActivity instanceof TPick){
					automataList.add(this.handlePick((TPick)subActivity, variables));
				}
				else
				//6.receive activity
				if(subActivity instanceof TReceive){
					automataList.add(this.handleReceive((TReceive)subActivity,variables));
				}
				else
				//7.reply activity
				if(subActivity instanceof TReply){
					automataList.add(this.handleReply((TReply)subActivity,variables));
				}
				else
				//8.switch activity
				if(subActivity instanceof TSwitch){
					automataList.add(this.handleSwitch((TSwitch)subActivity,variables));
				}
				else
				//9.terminate activity
				if(subActivity instanceof TTerminate){
					automataList.add(this.handleTerminate((TTerminate)subActivity));
				}
				else
				//10.wait activity
				if(subActivity instanceof TWait){
					automataList.add(this.handleWait((TWait)subActivity));
				}
				else
				//11.while activity
				if(subActivity instanceof TWhile){
					automataList.add(this.handleWhile((TWhile)subActivity, variables));
				}
				else
				//12.sequence activity
				if(subActivity instanceof TSequence){
					//TODO
					//TESTING WANTED.
					automataList.add(this.handleSequence((TSequence)subActivity, variables));
				}
				else{//TODO NOT any of above activities.
					
				}
			}
		}
		
		for(int j = 0; j < tSwitch.getOtherwise().eContents().size();j++){
			EObject subActivity = tSwitch.getOtherwise().eContents().get(j);
			
			//1.assign activity
			if(subActivity instanceof TAssign){
				automataList.add(this.handleAssign((TAssign)subActivity));
			}
			else
			//2.empty activity
			if(subActivity instanceof TEmpty){
				automataList.add(this.handleEmpty((TEmpty)subActivity));
			}
			else
			//3.flow activity
			if(subActivity instanceof TFlow){
				automataList.add(this.handleFlow((TFlow)subActivity, variables));
			}
			else
			//4.invoke activity
			if(subActivity instanceof TInvoke){
				automataList.add(this.handleInvoke((TInvoke)subActivity,variables));
			}
			else
			//5.pick activity
			if(subActivity instanceof TPick){
				automataList.add(this.handlePick((TPick)subActivity, variables));
			}
			else
			//6.receive activity
			if(subActivity instanceof TReceive){
				automataList.add(this.handleReceive((TReceive)subActivity,variables));
			}
			else
			//7.reply activity
			if(subActivity instanceof TReply){
				automataList.add(this.handleReply((TReply)subActivity,variables));
			}
			else
			//8.switch activity
			if(subActivity instanceof TSwitch){
				automataList.add(this.handleSwitch((TSwitch)subActivity,variables));
			}
			else
			//9.terminate activity
			if(subActivity instanceof TTerminate){
				automataList.add(this.handleTerminate((TTerminate)subActivity));
			}
			else
			//10.wait activity
			if(subActivity instanceof TWait){
				automataList.add(this.handleWait((TWait)subActivity));
			}
			else
			//11.while activity
			if(subActivity instanceof TWhile){
				automataList.add(this.handleWhile((TWhile)subActivity, variables));
			}
			else
			//12.sequence activity
			if(subActivity instanceof TSequence){
				//TODO
				//TESTING WANTED.
				automataList.add(this.handleSequence((TSequence)subActivity, variables));
			}
			else{//TODO NOT any of above activities.	
			}
		}
		
		
		//M = M1 + M2 + ... + Mn
		for(int i = 0; i < automataList.size(); i++){
			if(resultAutomata == null){
				resultAutomata = automataList.get(i);
				continue;
			}
			
			resultAutomata = resultAutomata.doANDUnion(automataList.get(i));
		}
		
		
		//add the TSwitch reference to start and final states 
		resultAutomata.getStartState().addSourceList(tSwitch);
		
		for(int i = 0; i < resultAutomata.getFinalStateSet().size(); i++){
			resultAutomata.getFinalStateSet().get(i).addTargetList(tSwitch);
		}
		
		return resultAutomata;
	}
	
	
	//echo RULE-8 of liumin's paper.
	//handle pick statement
	private SubAutomataImp handlePick(TPick pick,TVariables variables){
		LinkedList<SubAutomataImp> automataList = new LinkedList<SubAutomataImp>();
		SubAutomataImp resultAutomata = null;
		
		for(int i = 0; i < pick.eContents().size();i++){
			EObject subActivity = pick.eContents().get(i);
			
			if(subActivity instanceof TOnMessage){
				EObject superSubActivity = subActivity.eContents().get(0);
				SubAutomataImp onMessageAutomata = null;
				
				//1.assign activity
				if(superSubActivity instanceof TAssign){
					onMessageAutomata = this.handleAssign((TAssign)superSubActivity);
				}
				else
				//2.empty activity
				if(superSubActivity instanceof TEmpty){
					onMessageAutomata = this.handleEmpty((TEmpty)superSubActivity);
				}
				else
				//3.flow activity
				if(superSubActivity instanceof TFlow){
					onMessageAutomata = this.handleFlow((TFlow)superSubActivity, variables);
				}
				else
				//4.invoke activity
				if(superSubActivity instanceof TInvoke){
					onMessageAutomata = this.handleInvoke((TInvoke)superSubActivity,variables);
				}
				else
				//5.pick activity
				if(superSubActivity instanceof TPick){
					onMessageAutomata = this.handlePick((TPick)subActivity, variables);
				}
				else
				//6.receive activity
				if(superSubActivity instanceof TReceive){
					onMessageAutomata = this.handleReceive((TReceive)superSubActivity,variables);
				}
				else
				//7.reply activity
				if(superSubActivity instanceof TReply){
					onMessageAutomata = this.handleReply((TReply)superSubActivity,variables);
				}
				else
				//8.switch activity
				if(superSubActivity instanceof TSwitch){
					onMessageAutomata = this.handleSwitch((TSwitch)superSubActivity,variables);
				}
				else
				//9.terminate activity
				if(superSubActivity instanceof TTerminate){
					onMessageAutomata = this.handleTerminate((TTerminate)superSubActivity);
				}
				else
				//10.wait activity
				if(superSubActivity instanceof TWait){
					onMessageAutomata = this.handleWait((TWait)superSubActivity);
				}
				else
				//11.while activity
				if(superSubActivity instanceof TWhile){
					onMessageAutomata = this.handleWhile((TWhile)superSubActivity, variables);
				}
				else
				//12.sequence activity
				if(superSubActivity instanceof TSequence){
					//TODO
					//TESTING WANTED.
					onMessageAutomata = this.handleSequence((TSequence)superSubActivity, variables);
				}
				else{//TODO NOT any of above activities.
					
				}
				
				/*
				//add the TOnMessage reference to start and final states
				onMessageAutomata.getStartState().addSourceList((TOnMessage)subActivity);
				
				for(int j = 0; j < onMessageAutomata.getFinalStateSet().size(); j++){
					onMessageAutomata.getFinalStateSet().get(j).addTargetList((TOnMessage)subActivity);
				}
				*/
				
				
				TOnMessage onMessage = (TOnMessage)subActivity;
				SubAutomataImp automata = this.handleOnMessage(onMessage, variables);
				
				
				automataList.add(automata.doCatenation(onMessageAutomata));
			}
			else
			if(subActivity instanceof TOnAlarm){
				EObject superSubActivity = subActivity.eContents().get(0);
				SubAutomataImp onAlarmAutomata = null;
				
				//1.assign activity
				if(superSubActivity instanceof TAssign){
					onAlarmAutomata = this.handleAssign((TAssign)superSubActivity);
				}
				else
				//2.empty activity
				if(superSubActivity instanceof TEmpty){
					onAlarmAutomata = this.handleEmpty((TEmpty)superSubActivity);
				}
				else
				//3.flow activity
				if(superSubActivity instanceof TFlow){
					onAlarmAutomata = this.handleFlow((TFlow)superSubActivity, variables);
				}
				else
				//4.invoke activity
				if(superSubActivity instanceof TInvoke){
					onAlarmAutomata = this.handleInvoke((TInvoke)superSubActivity,variables);
				}
				else
				//5.pick activity
				if(superSubActivity instanceof TPick){
					onAlarmAutomata = this.handlePick((TPick)subActivity, variables);
				}
				else
				//6.receive activity
				if(superSubActivity instanceof TReceive){
					onAlarmAutomata = this.handleReceive((TReceive)superSubActivity,variables);
				}
				else
				//7.reply activity
				if(superSubActivity instanceof TReply){
					onAlarmAutomata = this.handleReply((TReply)superSubActivity,variables);
				}
				else
				//8.switch activity
				if(superSubActivity instanceof TSwitch){
					onAlarmAutomata = this.handleSwitch((TSwitch)superSubActivity,variables);
				}
				else
				//9.terminate activity
				if(superSubActivity instanceof TTerminate){
					onAlarmAutomata = this.handleTerminate((TTerminate)superSubActivity);
				}
				else
				//10.wait activity
				if(superSubActivity instanceof TWait){
					onAlarmAutomata = this.handleWait((TWait)superSubActivity);
				}
				else
				//11.while activity
				if(superSubActivity instanceof TWhile){
					onAlarmAutomata = this.handleWhile((TWhile)superSubActivity, variables);
				}
				else
				//12.sequence activity
				if(superSubActivity instanceof TSequence){
					//TODO
					//TESTING WANTED.
					onAlarmAutomata = this.handleSequence((TSequence)superSubActivity, variables);
				}
				else{//TODO NOT any of above activities.
					
				}
				
				
				//add the TOnAlarm reference to start and final states
				onAlarmAutomata.getStartState().addSourceList((TOnAlarm)subActivity);
				
				for(int j = 0; j < onAlarmAutomata.getFinalStateSet().size(); j++){
					onAlarmAutomata.getFinalStateSet().get(j).addTargetList((TOnAlarm)subActivity);
				}
				
				
				automataList.add(onAlarmAutomata);
			}
		}
		
		
		for(int i = 0; i < automataList.size(); i++){
			if(resultAutomata == null){
				resultAutomata = automataList.get(i);
				continue;
			}
			
			resultAutomata = resultAutomata.doORUnion(automataList.get(i));
		}
		
		
		//add the TPick reference to start and final states
		resultAutomata.getStartState().addSourceList(pick);
		
		for(int i = 0; i < resultAutomata.getFinalStateSet().size(); i++){
			resultAutomata.getFinalStateSet().get(i).addTargetList(pick);
		}
		
		
		return resultAutomata;
	}
	
	//internal method to handle OnMessage activities of Pick. 
	private SubAutomataImp handleOnMessage(TOnMessage onMessage,TVariables variables){
		//automata object generated from OnMessage
		SubAutomataImp automata = new SubAutomataImp();
		
		automata.getStartState().addSourceList(onMessage);
		
		
		//set state set.
		LinkedList<State> stateSet = new LinkedList<State>();
		State fstate = new State();
		
		stateSet.add(automata.getStartState());
		stateSet.add(fstate);
		
		automata.setStateSet(stateSet);
		
		
		//set final state [set].
		automata.setFinalStateSet(fstate);
		fstate.addTargetList(onMessage);
		
		
		//set message
		String mt = "";
		
		for(int k = 0; k < variables.getVariable().size();k++){
			if(variables.getVariable().get(k).getName().equals(onMessage.getVariable())){
				//$link
				//TODO ...getMessageType() returns an Object,maybe it's NOT the one I wanna get.
				QName qn = QNameUtil.translate(variables.getVariable().get(k).getMessageType());
				mt = qn.getNamespaceURI() + ":" + qn.getLocalPart();
				//System.err.println("\tgetMessageType() = " + mt);
				
				
				//ONLY accept the first one that matches the condition,as maybe
				//the BPEL file is not 100% correct.
				break;
			}
		}
		
		Message mes = new Message(onMessage.getPartnerLink(),onMessage.getPortType().toString(),onMessage.getOperation(),mt,Message.MESSAGE_DIRECTION_IN);
		
		//TODO TESTING WANTED.
		mes = Message.checkUnicity(automata.getMessageSet(), mes);
		
		automata.setMessageSet(mes);
		
		
		//set label function
		SimpleLogicalFormulaImp clf = new SimpleLogicalFormulaImp(automata.getStartState(),mes,fstate);
		SimpleLogicalFormulaImp clf2 = new SimpleLogicalFormulaImp(fstate,SimpleLogicalFormulaImp.VALID_LOGICAL_FORMULA);
		automata.getLabelFunction().add(clf);
		automata.getLabelFunction().add(clf2);
		
		
		//set transition function.
		TransitionRule tr = new TransitionRule(automata.getStartState(),mes,fstate);
		TransitionFunction tf = new TransitionFunction();
		tf.add(tr);
		
		automata.setTransitionFunction(tf);
		
		return automata;
	}
	
	
	//echo RULE-9 of liumin's paper.
	//handle while statement
	//ONLY one structural statement in while statement. 
	private SubAutomataImp handleWhile(TWhile tWhile,TVariables variables){
		LinkedList<SubAutomataImp> automataList = new LinkedList<SubAutomataImp>();
		SubAutomataImp resultAutomata = null;
		
		for(int i = 0; i < tWhile.eContents().size();i++){
			EObject subActivity = tWhile.eContents().get(i);
			
			//1.assign activity
			if(subActivity instanceof TAssign){
				automataList.add(this.handleAssign((TAssign)subActivity));
			}
			else
			//2.empty activity
			if(subActivity instanceof TEmpty){
				automataList.add(this.handleEmpty((TEmpty)subActivity));
			}
			else
			//3.flow activity
			if(subActivity instanceof TFlow){
				automataList.add(this.handleFlow((TFlow)subActivity, variables));
			}
			else
			//4.invoke activity
			if(subActivity instanceof TInvoke){
				automataList.add(this.handleInvoke((TInvoke)subActivity,variables));
			}
			else
			//5.pick activity
			if(subActivity instanceof TPick){
				automataList.add(this.handlePick((TPick)subActivity,variables));
			}
			else
			//6.receive activity
			if(subActivity instanceof TReceive){
				automataList.add(this.handleReceive((TReceive)subActivity,variables));
			}
			else
			//7.reply activity
			if(subActivity instanceof TReply){
				automataList.add(this.handleReply((TReply)subActivity,variables));
			}
			else
			//8.switch activity
			if(subActivity instanceof TSwitch){
				automataList.add(this.handleSwitch((TSwitch)subActivity,variables));
			}
			else
			//9.terminate activity
			if(subActivity instanceof TTerminate){
				automataList.add(this.handleTerminate((TTerminate)subActivity));
			}
			else
			//10.wait activity
			if(subActivity instanceof TWait){
				automataList.add(this.handleWait((TWait)subActivity));
			}
			else
			//11.while activity
			if(subActivity instanceof TWhile){
				automataList.add(this.handleWhile((TWhile)subActivity, variables));
			}
			else
			//12.sequence activity
			if(subActivity instanceof TSequence){
				//TODO
				//TESTING WANTED.
				automataList.add(this.handleSequence((TSequence)subActivity, variables));
			}
			else{//TODO NOT any of above activities.
			
			}
		}

		/*
		 * TODO
		 * TESTING WANTED.
		 * ONLY ONE ELEMENT IN THE LIST???
		 */
		//System.out.println("\t\tinfo@handleWhile() : automataList.size() = " + automataList.size());
		resultAutomata = automataList.get(0).doClosure();
		
		
		//add the TWhile reference to start and final states
		resultAutomata.getStartState().addSourceList(tWhile);
		
		for(int i = 0; i < resultAutomata.getFinalStateSet().size(); i++){
			resultAutomata.getFinalStateSet().get(i).addTargetList(tWhile);
		}
		
		
		return resultAutomata;
	}
	
	
	//echo RULE-10 of liumin's paper.
	//handle flow statement
	private SubAutomataImp handleFlow(TFlow flow,TVariables variables){
		LinkedList<SubAutomataImp> automataList = new LinkedList<SubAutomataImp>();
		SubAutomataImp resultAutomata = null;
		
		for(int i = 0; i < flow.eContents().size();i++){
			EObject subActivity = flow.eContents().get(i);
			
			//1.assign activity
			if(subActivity instanceof TAssign){
				automataList.add(this.handleAssign((TAssign)subActivity));
			}
			else
			//2.empty activity
			if(subActivity instanceof TEmpty){
				automataList.add(this.handleEmpty((TEmpty)subActivity));
			}
			else
			//3.flow activity
			if(subActivity instanceof TFlow){
				automataList.add(this.handleFlow((TFlow)subActivity, variables));
			}
			else
			//4.invoke activity
			if(subActivity instanceof TInvoke){
				automataList.add(this.handleInvoke((TInvoke)subActivity,variables));
			}
			else
			//5.pick activity
			if(subActivity instanceof TPick){
				automataList.add(this.handlePick((TPick)subActivity,variables));
			}
			else
			//6.receive activity
			if(subActivity instanceof TReceive){
				automataList.add(this.handleReceive((TReceive)subActivity,variables));
			}
			else
			//7.reply activity
			if(subActivity instanceof TReply){
				automataList.add(this.handleReply((TReply)subActivity,variables));
			}
			else
			//8.switch activity
			if(subActivity instanceof TSwitch){
				automataList.add(this.handleSwitch((TSwitch)subActivity,variables));
			}
			else
			//9.terminate activity
			if(subActivity instanceof TTerminate){
				automataList.add(this.handleTerminate((TTerminate)subActivity));
			}
			else
			//10.wait activity
			if(subActivity instanceof TWait){
				automataList.add(this.handleWait((TWait)subActivity));
			}
			else
			//11.while activity
			if(subActivity instanceof TWhile){
				automataList.add(this.handleWhile((TWhile)subActivity, variables));
			}
			else
			//12.sequence activity
			if(subActivity instanceof TSequence){
				//TODO
				//TESTING WANTED.
				automataList.add(this.handleSequence((TSequence)subActivity, variables));
			}
			else{//TODO NOT any of above activities.
			
			}
		}
		
		//do shuffle operation.
		for(int i = 0; i < automataList.size(); i++){
			if(resultAutomata == null){
				resultAutomata = automataList.get(i);
				continue;
			}
			
			resultAutomata = resultAutomata.doShuffle(automataList.get(i));
		}
		
		
		//add the TFlow reference to start and final states
		resultAutomata.getStartState().addSourceList(flow);
		
		for(int i = 0; i < resultAutomata.getFinalStateSet().size(); i++){
			resultAutomata.getFinalStateSet().get(i).addTargetList(flow);
		}
		
		
		return resultAutomata;
	}
}
